package ch.elexis.core.mail.internal; import java.io.File; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.AuthenticationFailedException; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Store; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.elexis.core.data.activator.CoreHub; import ch.elexis.core.mail.IMailClient; import ch.elexis.core.mail.MailAccount; import ch.elexis.core.mail.MailAccount.TYPE; import ch.elexis.core.mail.MailMessage; @Component public class MailClient implements IMailClient { private static final Logger logger = LoggerFactory.getLogger(MailClient.class); private static final String CONFIG_ACCOUNTS = "ch.elexis.core.mail/accounts"; private static final String CONFIG_ACCOUNT = "ch.elexis.core.mail/account"; private static final String ACCOUNTS_SEPARATOR = ","; private ErrorTyp lastError; @Override public Optional<ErrorTyp> getLastError(){ ErrorTyp ret = lastError; lastError = null; return Optional.ofNullable(ret); } @Override public Optional<MailAccount> getAccount(String id){ MailAccount ret = null; String accountString = CoreHub.globalCfg.get(CONFIG_ACCOUNT + "/" + id, null); if (accountString != null) { ret = MailAccount.from(accountString); } return Optional.ofNullable(ret); } @Override public List<String> getAccounts(){ List<String> ret = new ArrayList<String>(); String accountIds = CoreHub.globalCfg.get(CONFIG_ACCOUNTS, null); if (accountIds != null) { String[] currentIds = accountIds.split(ACCOUNTS_SEPARATOR); ret.addAll(Arrays.asList(currentIds)); } return ret; } @Override public void saveAccount(MailAccount account){ if (account != null && account.getId() != null) { addAccountId(account.getId()); CoreHub.globalCfg.set(CONFIG_ACCOUNT + "/" + account.getId(), account.toString()); CoreHub.globalCfg.flush(); } } private void addAccountId(String id){ if (id.contains(ACCOUNTS_SEPARATOR)) { throw new IllegalStateException( "Id can not contain separator [" + ACCOUNTS_SEPARATOR + "]"); } String accountIds = CoreHub.globalCfg.get(CONFIG_ACCOUNTS, null); if (accountIds == null) { CoreHub.globalCfg.set(CONFIG_ACCOUNTS, id); } else { String[] currentIds = accountIds.split(ACCOUNTS_SEPARATOR); for (String string : currentIds) { if (string.equals(id)) { return; } } // not already in list CoreHub.globalCfg.set(CONFIG_ACCOUNTS, accountIds + ACCOUNTS_SEPARATOR + id); CoreHub.globalCfg.flush(); } } @Override public void removeAccount(MailAccount account){ if (account != null && account.getId() != null) { removeAccountId(account.getId()); CoreHub.globalCfg.remove(CONFIG_ACCOUNT + "/" + account.getId()); CoreHub.globalCfg.flush(); } } private void removeAccountId(String id){ String accountIds = CoreHub.globalCfg.get(CONFIG_ACCOUNTS, null); if (accountIds != null) { StringBuilder sb = new StringBuilder(); String[] currentIds = accountIds.split(ACCOUNTS_SEPARATOR); for (String string : currentIds) { if (!string.equals(id)) { if (sb.length() > 0) { sb.append(ACCOUNTS_SEPARATOR); } sb.append(string); } } // write new list CoreHub.globalCfg.set(CONFIG_ACCOUNTS, sb.toString()); CoreHub.globalCfg.flush(); } } @Override public boolean testAccount(MailAccount account){ MailClientProperties properties = new MailClientProperties(account); try { if (account.getType() == TYPE.SMTP) { Session session = Session.getInstance(properties.getProperties(), new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication(account.getUsername(), account.getPassword()); } }); Transport transport = session.getTransport(); transport.connect(); transport.close(); } else if (account.getType() == TYPE.IMAP) { Session session = Session.getInstance(properties.getProperties(), new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication(account.getUsername(), account.getPassword()); } }); Store store = session.getStore("imaps"); store.connect(); store.close(); } else { logger.warn("Unknown account type [" + account.getType() + "]."); lastError = ErrorTyp.CONFIGTYP; return false; } } catch (MessagingException e) { logger.warn("Error testing account [" + account.getId() + "]", e); handleException(e); return false; } return true; } @Override public boolean sendMail(MailAccount account, MailMessage message){ MailClientProperties properties = new MailClientProperties(account); try { if (account.getType() == TYPE.SMTP) { Session session = Session.getInstance(properties.getProperties(), new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication(){ return new PasswordAuthentication(account.getUsername(), account.getPassword()); } }); MimeMessage mimeMessage = new MimeMessage(session); mimeMessage.addHeader("X-ElexisMail", "ch.elexis.core.mail"); // mail.user attribute of the properties mimeMessage.setFrom(account.getFromAddress()); mimeMessage.setSubject(message.getSubject()); Multipart multipart = new MimeMultipart(); // create the message part MimeBodyPart messageBodyPart = new MimeBodyPart(); messageBodyPart.setText(message.getText()); multipart.addBodyPart(messageBodyPart); if (message.hasAttachments()) { List<File> attachments = message.getAttachments(); for (File file : attachments) { messageBodyPart = new MimeBodyPart(); DataSource source = new FileDataSource(file); messageBodyPart.setDataHandler(new DataHandler(source)); messageBodyPart.setFileName(file.getName()); multipart.addBodyPart(messageBodyPart); } } // Put parts in message mimeMessage.setContent(multipart); Transport transport = session.getTransport(); transport.connect(); transport.sendMessage(mimeMessage, message.getToAddress()); transport.close(); } else { logger.warn("Invalid account type for sending [" + account.getType() + "]."); lastError = ErrorTyp.CONFIGTYP; return false; } } catch (MessagingException e) { logger.warn("Error sending using account [" + account.getId() + "]", e); handleException(e); return false; } return true; } private void handleException(MessagingException e){ if (e instanceof AuthenticationFailedException) { lastError = ErrorTyp.AUTHENTICATION; } else if (e.getNextException() instanceof UnknownHostException) { lastError = ErrorTyp.CONNECTION; } else if (e instanceof AddressException) { lastError = ErrorTyp.ADDRESS; } } }